package sys_serv

import (
	"encoding/json"
	"strconv"
	"strings"
	"ubt-gin-admin/app/api/model/sys_mod"
	"ubt-gin-admin/app/pkg/db"
	"ubt-gin-admin/app/pkg/enums"
	"ubt-gin-admin/app/utils"

	"github.com/gin-gonic/gin"
)

type sysUser struct{}

var SysUserServ = sysUser{}

// Login 用户登录
func (s *sysUser) Login(ctx *gin.Context, req *sys_mod.SysUserLoginReq) (string, string, map[string]any) {
	sqlStr := `SELECT a.user_id, a.usname, a.nick_name, a.mobile, a.dept_id, a.states, a.kind, b.role_name, b.data_role, b.menu_codes, b.btn_codes, b.data_role 
		FROM sys_user a LEFT JOIN sys_role b ON a.role_id=b.role_id WHERE a.usname=$1 AND a.passwd=$2`
	if _, _, dbMap := db.GetOne(sqlStr, req.Usname, req.Passwd); len(dbMap) > 0 {
		dbMap["clientIp"] = utils.IpAddr(ctx)
		if userJson, err := json.Marshal(dbMap); err == nil {
			// 将数据存储到Redis缓冲数据库中，键为随机的编号，值为获取到的用户信息数据
			userStr := string(userJson)
			token := utils.NewNanoid(21)
			utils.SaveUserInfo(ctx, token, userStr)
			data := make(map[string]any, 0)
			data["token"] = token
			data["userId"] = dbMap["userId"]
			return enums.Succeed.Code, enums.Succeed.Msg, data
		}
		if dbMap["states"] != 1 {
			return enums.UnPass.Code, enums.UnPass.Msg, nil
		}
	}
	return enums.UserErr.Code, enums.UserErr.Msg, nil
}

// Exit 用户登出
func (s *sysUser) Exit(ctx *gin.Context, req *sys_mod.SysUserExitReq) (string, string) {
	utils.CleanUserInfo(ctx, req)
	return enums.Succeed.Code, enums.Succeed.Msg
}

// Add 新增用户
func (s *sysUser) Add(req *sys_mod.SysUserSaveReq) (string, string) {
	sqlStr := `INSERT INTO sys_user(usname, passwd, nick_name, mobile, role_id, dept_id, kind, states, add_time, upd_time) 
		VALUES ($1, $2, $3, $4, $5, $6, $7, 1, EXTRACT(epoch FROM NOW()), EXTRACT(epoch FROM NOW()))`
	return db.CudData(sqlStr, req.Usname, req.Passwd, req.NickName, req.Mobile, req.RoleId, req.DeptId, req.Kind)
}

// Exists 判断平台编码是否存在
func (s *sysUser) Exists(req *sys_mod.SysUserExtVo) bool {
	sqlStr := "SELECT user_id FROM sys_user WHERE states!=2 AND (usname=$1 OR mobile=$2)"
	param := make([]any, 0)
	param = append(param, req.Usname)
	param = append(param, req.Mobile)
	if req.UserId != "" {
		sqlStr += " AND user_id!=$3"
		param = append(param, req.UserId)
	}
	if _, _, data := db.GetOne(sqlStr, param...); len(data) == 0 {
		return false
	}
	return true
}

// Update 修改用户
func (s *sysUser) Update(req *sys_mod.SysUserSaveReq) (string, string) {
	var sqlStr string
	if req.Passwd != "" {
		sqlStr = "UPDATE sys_user SET usname=$1, passwd=$2, nick_name=$3, mobile=$4, role_id=$5, dept_id=$6, kind=$7, upd_time=EXTRACT(epoch FROM NOW()) WHERE user_id=$8"
		return db.CudData(sqlStr, req.Usname, req.Passwd, req.NickName, req.Mobile, req.RoleId, req.DeptId, req.Kind, req.UserId)
	} else {
		sqlStr = "UPDATE sys_user SET usname=$1, nick_name=$2, mobile=$3, role_id=$4, dept_id=$5, kind=$6, upd_time=EXTRACT(epoch FROM NOW()) WHERE user_id=$7"
		return db.CudData(sqlStr, req.Usname, req.NickName, req.Mobile, req.RoleId, req.DeptId, req.Kind, req.UserId)
	}
}

// Process 处理用户
func (s *sysUser) Process(req *sys_mod.SysUserProReq) (string, string) {
	var (
		param []any
		q     string
		n     = 1
	)
	param = append(param, req.States)
	idList := strings.Split(req.UserIds, ",")
	for _, curId := range idList {
		n++
		q += "$" + strconv.Itoa(n) + ","
		param = append(param, curId)
	}
	q = q[:len(q)-1]
	sqlStr := "UPDATE sys_user SET states=$1, upd_time=EXTRACT(epoch FROM NOW()) WHERE user_id IN (" + q + ")"
	return db.CudData(sqlStr, param...)
}

// GetPasswd 获取用户密码
func (s *sysUser) GetPasswd(userId string) string {
	sqlStr := "SELECT passwd FROM sys_user WHERE user_id=$1"
	if _, _, data := db.GetOne(sqlStr, userId); len(data) > 0 {
		return data["passwd"].(string)
	}
	return ""
}

// Personal 修改个人资料
func (s *sysUser) Personal(req *sys_mod.SysUserInfoReq) (string, string) {
	var sqlStr string
	if req.NewPasswd != "" {
		sqlStr = "UPDATE sys_user SET usname=$1, passwd=$2, nick_name=$3, mobile=$4, upd_time=EXTRACT(epoch FROM NOW()) WHERE user_id=$5"
		return db.CudData(sqlStr, req.Usname, req.NewPasswd, req.NickName, req.Mobile, req.UserId)
	} else {
		sqlStr = "UPDATE sys_user SET usname=$1, nick_name=$2, mobile=$3, upd_time=EXTRACT(epoch FROM NOW()) WHERE user_id=$4"
		return db.CudData(sqlStr, req.Usname, req.NickName, req.Mobile, req.UserId)
	}
}

// One 获取用户详情
func (s *sysUser) One(userId string) (string, string, map[string]any) {
	sqlStr := `SELECT a.user_id, a.usname, '' AS passwd, a.nick_name, a.mobile, a.role_id, b.role_name, b.role_code, 
		a.kind, a.states, a.add_time, a.upd_time, a.dept_id, c.dict_name AS dept_name, c.dict_code AS dept_code 
		FROM sys_user a 
		LEFT JOIN sys_role b ON a.role_id=b.role_id 
		LEFT JOIN sys_dict c ON c.states=1 AND c.kind=2 AND c.type_code='SYS_DEPT' AND a.dept_id=c.dict_id 
		WHERE a.user_id=$1`
	return db.GetOne(sqlStr, userId)
}

// Count 获取用户数量
func (s *sysUser) Count(req *sys_mod.SysUserPageReq) (string, string, any) {
	sqlStr := "SELECT COUNT(1) AS nums FROM sys_user WHERE states!=2"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "usname LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"nick_name LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"mobile LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 3
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.DeptId != "" {
		n++
		sqlStr += " AND dept_id=$" + strconv.Itoa(n)
		param = append(param, req.DeptId)
	}
	if req.RoleId != "" {
		n++
		sqlStr += " AND role_id=$" + strconv.Itoa(n)
		param = append(param, req.RoleId)
	}
	if req.States > 0 {
		n++
		sqlStr += " AND states=$" + strconv.Itoa(n)
		param = append(param, req.States)
	}
	if code, msg, data := db.GetOne(sqlStr, param...); len(data) > 0 && data["nums"].(int64) > 0 {
		return code, msg, data["nums"]
	}
	return enums.NoData.Code, enums.NoData.Msg, 0
}

// Page 获取用户分页列表
func (s *sysUser) Page(req *sys_mod.SysUserPageReq) (string, string, any) {
	sqlStr := "SELECT a.user_id, a.usname, a.nick_name, a.mobile, b.role_name, a.kind, c.dict_name dept_name, a.states " +
		"FROM sys_user a " +
		"LEFT JOIN sys_role b ON a.role_id=b.role_id " +
		"LEFT JOIN sys_dict c ON c.states=1 AND c.kind=2 AND c.type_code='SYS_DEPT' AND a.dept_id=c.dict_id " +
		"WHERE a.states!=2"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "a.usname LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"a.nick_name LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"a.mobile LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 3
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.DeptId != "" {
		n++
		sqlStr += " AND a.dept_id=$" + strconv.Itoa(n)
		param = append(param, req.DeptId)
	}
	if req.RoleId != "" {
		n++
		sqlStr += " AND a.role_id=$" + strconv.Itoa(n)
		param = append(param, req.RoleId)
	}
	if req.States > 0 {
		n++
		sqlStr += " AND a.states=$" + strconv.Itoa(n)
		param = append(param, req.States)
	}
	sqlStr += " ORDER BY a.upd_time DESC LIMIT $" + strconv.Itoa(n+1) + " OFFSET $" + strconv.Itoa(n+2)
	param = append(param, req.Limit)
	param = append(param, req.Offset)
	return db.GetAll(sqlStr, param...)
}

// Select 获取用户下拉列表
func (s *sysUser) Select(req *sys_mod.SysUserSelReq) (string, string, any) {
	sqlStr := "SELECT user_id sel_id, nick_name sel_name, usname sel_code, false chked FROM sys_user WHERE states=1"
	param := make([]any, 0)
	var n = 0
	if req.DeptId != "" {
		n++
		sqlStr += " AND dept_id=$" + strconv.Itoa(n)
		param = append(param, req.DeptId)
	}
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "usname LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"nick_name LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"mobile LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 3
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	sqlStr += " ORDER BY nick_name"
	return db.GetAll(sqlStr, param...)
}

// SelCount 获取用户数量
func (s *sysUser) SelCount(req *sys_mod.SysUserSelReq) (string, string, any) {
	sqlStr := "SELECT COUNT(1) AS nums FROM sys_user WHERE states=1"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "usname LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"nick_name LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"mobile LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 3
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.DeptId != "" {
		n++
		sqlStr += " AND dept_id=$" + strconv.Itoa(n)
		param = append(param, req.DeptId)
	}
	if code, msg, data := db.GetOne(sqlStr, param...); len(data) > 0 && data["nums"].(int64) > 0 {
		return code, msg, data["nums"]
	}
	return enums.NoData.Code, enums.NoData.Msg, 0
}

// SelPage 获取用户分页列表
func (s *sysUser) SelPage(req *sys_mod.SysUserSelReq) (string, string, any) {
	sqlStr := "SELECT (a.dept_id||'@_@'||a.user_id) user_id, a.nick_name, c.dict_name AS dept_name, c.dict_code AS dept_code, b.role_name, false chked " +
		"FROM sys_user a " +
		"LEFT JOIN sys_role b ON a.role_id=b.role_id " +
		"LEFT JOIN sys_dict c ON c.states=1 AND c.kind=2 AND c.type_code='SYS_DEPT' AND a.dept_id=c.dict_id " +
		"WHERE a.states=1"
	param := make([]any, 0)
	var n = 0
	if req.Keywords != "" {
		sqlStr += " AND ("
		nameArr := strings.Split(req.Keywords, " ")
		for _, name := range nameArr {
			sqlStr += "a.usname LIKE '%'||$" + strconv.Itoa(n+1) + "||'%' OR " +
				"a.nick_name LIKE '%'||$" + strconv.Itoa(n+2) + "||'%' OR " +
				"a.mobile LIKE '%'||$" + strconv.Itoa(n+3) + "||'%' OR "
			param = append(param, name)
			param = append(param, name)
			param = append(param, name)
			n += 3
		}
		sqlStr = sqlStr[:len(sqlStr)-4]
		sqlStr += ")"
	}
	if req.DeptId != "" {
		n++
		sqlStr += " AND a.dept_id=$" + strconv.Itoa(n)
		param = append(param, req.DeptId)
	}
	sqlStr += " ORDER BY a.upd_time DESC LIMIT $" + strconv.Itoa(n+1) + " OFFSET $" + strconv.Itoa(n+2)
	param = append(param, req.Limit)
	param = append(param, req.Offset)
	return db.GetAll(sqlStr, param...)
}
